/**
 * Notes: 支付模块业务逻辑 - 宠物门店预约小程序
 * Date: 2025-01-27 
 */

const BaseService = require('./base_service.js');
const AppointmentModel = require('../model/appointment_model.js');
const UserModel = require('../model/user_model.js');
const RechargeModel = require('../model/recharge_model.js');
const timeUtil = require('../../framework/utils/time_util.js');
// 新增：引入配置、加解密与文件读取
const config = require('../../config/config.js');
const crypto = require('crypto');
const fs = require('fs');
let WxPay;
const path = require('path');
const DeviceOrderModel = require('../model/device_order_model.js');
const PassportService = require('./passport_service.js');
// 云函数调用封装
const cloudBase = require('../../framework/cloud/cloud_base.js');

class PaymentService extends BaseService {

	/**
	 * 确保用户存在（若不存在则自动建档）
	 * @param {string} userId 用户ID（openid）
	 * @param {Object} userInfo 可选的用户信息（用于自动建档）
	 * @returns {Object|null} 用户信息对象，失败返回 null
	 */
	async ensureUserExists(userId, userInfo = {}) {
		if (!userId) return null;

		// 查询用户是否存在
		let user = await UserModel.getOne({ _id: userId });
		if (user) return user;

		// 不存在则尝试自动建档
		try {
			const passportSvc = new PassportService();
			user = await passportSvc.registerUser(userId, userInfo);
			return user;
		} catch (err) {
			console.error('ensureUserExists 自动建档失败:', err);
			return null;
		}
	}

	/**
	 * 创建支付订单
	 * @param {string} appointmentId 预约ID
	 * @param {string} userId 用户ID
	 * @returns {Object} 支付参数
	 */
	async createPayment(appointmentId, userId) {
		// 获取预约信息
		const appointment = await AppointmentModel.getOne({
			_id: appointmentId,
			userId: userId
		});

		if (!appointment) {
			throw new Error('预约单不存在或无权限操作');
		}

		// 检查预约状态
		if (appointment.status !== AppointmentModel.STATUS.PENDING_PAY) {
			throw new Error('预约单状态不允许支付');
		}

		// 检查预约时间是否已过期（预约时间小于当前时间）
		const currentTime = timeUtil.time() / 1000; // 转换为秒时间戳
		if (appointment.appointmentTime < currentTime) {
			// 预约时间已过期，自动取消订单
			await AppointmentModel.edit({ _id: appointmentId }, {
				status: AppointmentModel.STATUS.CANCELLED,
				updateTime: timeUtil.time()
			});
			throw new Error('预约时间已过期，订单已自动取消，请重新预约');
		}

		// 生成支付参数
		const paymentParams = await this.generatePaymentParams(appointment);
		// 在调试模式且未启用真实微信支付时，标记前端模拟支付
		if (config && config.TEST_MODE && !config.TEST_CONFIG.ENABLE_REAL_WECHAT_PAY) {
			paymentParams._isTestMode = true;
		}

		return {
			appointmentId: appointmentId,
			appointmentNumber: appointment.appointmentNumber,
			totalAmount: appointment.totalAmount,
			payAmount: appointment.payAmount,
			paymentParams: paymentParams
		};
	}

	/**
	 * 处理支付回调
	 * @param {string} appointmentId 预约ID
	 * @param {Object} paymentResult 支付结果
	 * @returns {Object} 处理结果
	 */
	async handlePaymentCallback(appointmentId, paymentResult) {
		const { transactionId, payTime, status } = paymentResult;

		// 获取预约信息
		const appointment = await AppointmentModel.getOne({ _id: appointmentId });
		if (!appointment) {
			throw new Error('预约单不存在');
		}

		// 检查预约状态
		if (appointment.status !== AppointmentModel.STATUS.PENDING_PAY) {
			throw new Error('预约单状态不允许支付');
		}

		if (status === 'success') {
			// 支付成功前进行容量二次校验（排除当前预约自身）
			try {
				const AppointmentService = require('./appointment_service.js');
				const apptSvc = new AppointmentService();
				await apptSvc.checkTimeConflict(
					appointment.storeId,
					appointment.serviceId,
					appointment.appointmentTime,
					appointment.appointmentEndTime,
					appointment.employeeId || '',
					appointment.deviceId || '',
					appointment._id
				);
			} catch (e) {
				// 容量不足：取消预约并返回失败，同时触发自动退款
				await this.initiateWechatRefundForAppointment(appointment, '容量不足自动退款');
				await AppointmentModel.edit({ _id: appointmentId }, {
					status: AppointmentModel.STATUS.CANCELLED,
					updateTime: timeUtil.time()
				});
				return {
					success: false,
					message: '容量不足，支付失败：' + (e && e.message ? e.message : '请重新选择时间/房型')
				};
			}

			// 容量校验通过，更新预约状态
			await AppointmentModel.edit({ _id: appointmentId }, {
				status: AppointmentModel.STATUS.PAID,
				payTime: payTime || timeUtil.time(),
				updateTime: timeUtil.time()
			});

			return {
				success: true,
				message: '支付成功',
				appointmentId: appointmentId
			};
		} else {
			// 支付失败
			return {
				success: false,
				message: '支付失败',
				appointmentId: appointmentId
			};
		}
	}

	/**
	 * 余额支付
	 * @param {string} appointmentId 预约ID
	 * @param {string} userId 用户ID
	 * @returns {Object} 支付结果
	 */
	async payWithBalance(appointmentId, userId) {
		// 获取预约信息
		const appointment = await AppointmentModel.getOne({
			_id: appointmentId,
			userId: userId
		});

		if (!appointment) {
			throw new Error('预约单不存在或无权限操作');
		}

		// 检查预约状态
		if (appointment.status !== AppointmentModel.STATUS.PENDING_PAY) {
			throw new Error('预约单状态不允许支付');
		}

		// 获取用户信息（兜底自动建档）
		const user = await this.ensureUserExists(userId);
		if (!user) {
		    throw new Error('用户不存在');
		}

		// 检查余额
		if (user.balance < appointment.payAmount) {
			throw new Error('余额不足');
		}

		// 容量二次校验（排除当前预约自身）
		try {
			const AppointmentService = require('./appointment_service.js');
			const apptSvc = new AppointmentService();
			await apptSvc.checkTimeConflict(
				appointment.storeId,
				appointment.serviceId,
				appointment.appointmentTime,
				appointment.appointmentEndTime,
				appointment.employeeId || '',
				appointment.deviceId || '',
				appointment._id
			);
		} catch (e) {
			throw new Error('容量不足，余额支付失败：' + (e && e.message ? e.message : '请重新选择时间/房型'));
		}

		// 扣除余额
		await UserModel.edit({ _id: userId }, {
			balance: user.balance - appointment.payAmount,
			updateTime: timeUtil.time()
		});

		// 更新预约状态
		await AppointmentModel.edit({ _id: appointmentId }, {
			status: AppointmentModel.STATUS.PAID,
			payTime: timeUtil.time(),
			updateTime: timeUtil.time()
		});

		return {
			success: true,
			message: '支付成功',
			appointmentId: appointmentId,
			remainingBalance: user.balance - appointment.payAmount
		};
	}

	/**
	 * 申请退款
	 * @param {string} appointmentId 预约ID
	 * @param {string} userId 用户ID
	 * @param {string} reason 退款原因
	 * @returns {Object} 退款结果
	 */
	async requestRefund(appointmentId, userId, reason) {
		// 获取预约信息
		const appointment = await AppointmentModel.getOne({
			_id: appointmentId,
			userId: userId
		});

		if (!appointment) {
			throw new Error('预约单不存在或无权限操作');
		}

		// 检查预约状态
		if (appointment.status !== AppointmentModel.STATUS.PAID) {
			throw new Error('只有已支付的预约单才能申请退款');
		}

		// 检查是否在退款期限内（例如：预约时间前2小时）
		const now = timeUtil.time();
		const refundDeadline = appointment.appointmentTime - (2 * 60 * 60); // 2小时前
		
		if (now > refundDeadline) {
			throw new Error('已超过退款期限');
		}

		// 这里应该调用实际的退款接口
		// 暂时模拟退款成功
		const refundResult = await this.processRefund(appointment);

		if (refundResult.success) {
			// 更新预约状态为已取消
			await AppointmentModel.edit({ _id: appointmentId }, {
				status: AppointmentModel.STATUS.CANCELLED,
				updateTime: timeUtil.time()
			});

			// 退还余额
			await this.refundToBalance(userId, appointment.payAmount);

			return {
				success: true,
				message: '退款申请成功',
				refundAmount: appointment.payAmount
			};
		} else {
			throw new Error('退款申请失败');
		}
	}

	/**
	 * 获取用户交易记录
	 * @param {string} userId 用户ID
	 * @param {number} page 页码
	 * @param {number} size 每页数量
	 * @returns {Object} 交易记录
	 */
	async getTransactionRecords(userId, page = 1, size = 20) {
		let where = { userId: userId };
		let fields = '_id,appointmentNumber,appointmentTime,status,totalAmount,payAmount,payTime,createTime';
		let orderBy = { createTime: -1 };

		const result = await AppointmentModel.getList(where, fields, orderBy, page, size, true, 0);
		
		// 转换交易记录格式
		const records = result.list.map(appointment => ({
			id: appointment._id,
			appointmentNumber: appointment.appointmentNumber,
			type: this.getTransactionType(appointment.status),
			amount: appointment.payAmount,
			status: this.getTransactionStatus(appointment.status),
			time: appointment.payTime || appointment.createTime,
			description: this.getTransactionDescription(appointment)
		}));

		return {
			list: records,
			total: result.total,
			page: page,
			size: size
		};
	}

	/**
	 * 生成支付参数
	 * @param {Object} appointment 预约信息
	 * @returns {Object} 支付参数
	 */
	async generatePaymentParams(appointment) {
		// 容量二次校验（防并发超售）
		try {
			const AppointmentService = require('./appointment_service.js');
			const apptSvc = new AppointmentService();
			await apptSvc.checkTimeConflict(
				appointment.storeId,
				appointment.serviceId,
				appointment.appointmentTime,
				appointment.appointmentEndTime,
				appointment.employeeId || '',
				appointment.deviceId || '',
				appointment._id || appointment.id || null
			);
		} catch (e) {
			console.warn('[CapacityCheck] 生成支付参数前校验失败:', e && e.message ? e.message : e);
			throw new Error('容量校验失败：' + (e && e.message ? e.message : '请重新选择时间/房型'));
		}

		// 获取用户 openid（系统中 userId 等同于 openid）
		const user = await this.ensureUserExists(appointment.userId);
		if (!user) throw new Error('用户不存在');

		// 修正并清洗通知地址，去除反引号与空格
		let notifyBase = (config.WXPAY.NOTIFY_BASE_URL || '').toString().trim().replace(/^`|`$/g, '');
		const notifyPath = (config.WXPAY.NOTIFY_APPOINTMENT_PATH || '').toString().trim().replace(/^`|`$/g, '');
		// 确保 notifyBase 包含 https:// 协议
		if (notifyBase && !notifyBase.startsWith('http://') && !notifyBase.startsWith('https://')) {
			notifyBase = 'https://' + notifyBase;
		}
		const notifyUrl = `${notifyBase}${notifyPath}`;
		console.log('[Appointment] JSAPI notify_url:', notifyUrl);
		const amountTotal = config.WXPAY.FORCE_ONE_CENT ? 1 : appointment.payAmount;
		if (config.WXPAY.FORCE_ONE_CENT) console.warn('[ForceOneCent] Appointment JSAPI amount forced to 1 cent');

		// 若未启用真实微信支付，返回模拟支付参数
		if (!config.TEST_CONFIG.ENABLE_REAL_WECHAT_PAY) {
			console.log('[Appointment] 测试模式，返回模拟支付参数');
			const payParams = {
				timeStamp: String(Math.floor(Date.now() / 1000)),
				nonceStr: Math.random().toString(36).slice(2, 18),
				package: `prepay_id=wx_test_${appointment.appointmentNumber}_${Date.now()}`,
				signType: 'RSA',
				paySign: 'test_pay_sign_' + Math.random().toString(36).slice(2, 18),
				_isTestMode: true
			};
			console.log('[Appointment] 返回模拟支付参数:', payParams);
			return payParams;
		}

		// 启用真实微信支付：直接使用 wechatpay-node-v3
		try {
			const wxPay = this._getWxPayClient();
			const params = {
				appid: config.WXPAY.APPID,
				mchid: config.WXPAY.MCHID,
				description: `预约支付-${appointment.appointmentNumber}`,
				out_trade_no: appointment.appointmentNumber,
				notify_url: notifyUrl,
				amount: { total: amountTotal },
				payer: { openid: user._id },
			};
			console.log('[Appointment] 微信支付请求参数:', JSON.stringify(params, null, 2));
			const result = await wxPay.transactions_jsapi(params);
			console.log('[Appointment] 微信支付原始响应:', JSON.stringify(result, null, 2));
			const resData = result && (result.data || result);
			console.log('[Appointment] 提取的响应数据:', JSON.stringify(resData, null, 2));
			let payParams;
			if (resData && resData.package && (resData.paySign || resData.sign)) {
				payParams = {
					timeStamp: String(resData.timeStamp || resData.timestamp || Math.floor(Date.now() / 1000)),
					nonceStr: resData.nonceStr || resData.noncestr || (this.generateNonceStr ? this.generateNonceStr() : Math.random().toString(36).slice(2, 18)),
					package: resData.package,
					signType: resData.signType || 'RSA',
					paySign: resData.paySign || resData.sign,
				};
			} else {
				let prepayId = resData && resData.prepay_id;
				if (!prepayId && resData && typeof resData.package === 'string' && resData.package.startsWith('prepay_id=')) {
					prepayId = resData.package.replace('prepay_id=', '').trim();
				}
				console.log('[Appointment] 提取到的 prepay_id:', prepayId);
				if (!prepayId) throw new Error('微信下单失败：未返回 prepay_id');
				const appId = config.WXPAY.APPID;
				const timeStamp = String(Math.floor(Date.now() / 1000));
				const nonceStr = this.generateNonceStr ? this.generateNonceStr() : Math.random().toString(36).slice(2, 18);
				const payPackage = `prepay_id=${prepayId}`;
				const message = `${appId}\n${timeStamp}\n${nonceStr}\n${payPackage}\n`;
				const privateKeyPem = fs.readFileSync(config.WXPAY.MCH_PRIVKEY_PATH, 'utf8');
				const signer = crypto.createSign('RSA-SHA256');
				signer.update(message, 'utf8');
				signer.end();
				const paySign = signer.sign(privateKeyPem, 'base64');
				payParams = { timeStamp, nonceStr, package: payPackage, signType: 'RSA', paySign };
			}
			console.log('[Appointment] 返回支付参数:', payParams);
			return payParams;
		} catch (error) {
			console.error('[Appointment] 微信支付调用失败:', error);
			console.error('[Appointment] 错误详情:', {
				message: error.message,
				stack: error.stack,
				code: error.code,
				response: error.response,
				data: error.data
			});
			throw new Error(`微信支付调用失败: ${error.message}`);
		}
	}
	/**
	 * 处理退款
	 * @param {Object} appointment 预约信息
	 * @returns {Object} 退款结果
	 */
	async processRefund(appointment) {
		// 这里应该调用微信支付退款API
		// 暂时模拟退款成功
		return new Promise((resolve) => {
			setTimeout(() => {
				resolve({
					success: true,
					refundId: 'refund_' + Date.now(),
					refundAmount: appointment.payAmount
				});
			}, 1000);
		});
	}

	/**
	 * 自动触发微信退款：用于容量不足等异常场景
	 * @param {Object} appointment 预约信息
	 * @param {string} reason 退款原因
	 */
	async initiateWechatRefundForAppointment(appointment, reason = '容量不足自动退款') {
		try {
			// 测试模式：直接走模拟退款
			if (config.TEST_MODE && !config.TEST_CONFIG.ENABLE_REAL_WECHAT_PAY) {
				console.warn('[Refund][TEST_MODE] 模拟触发退款:', { appointmentNumber: appointment.appointmentNumber, amount: appointment.payAmount });
				await this.processRefund(appointment);
				return { success: true, mode: 'test' };
			}

			const wxPay = this._getWxPayClient();
			const refundAmount = config.WXPAY.FORCE_ONE_CENT ? 1 : appointment.payAmount;
			const params = {
				out_trade_no: appointment.appointmentNumber,
				out_refund_no: `RF_${appointment.appointmentNumber}_${Date.now()}`,
				reason,
				amount: { refund: refundAmount, total: refundAmount, currency: 'CNY' }
			};
			console.log('[Refund] Initiating WeChat refund:', params);
			const res = typeof wxPay.refunds === 'function' ? await wxPay.refunds(params) : null;
			if (!res) {
				console.error('[Refund] wxPay.refunds method not available on client');
				return { success: false, error: new Error('refunds method not available') };
			}
			console.log('[Refund] WeChat refund response:', res && (res.data || res));
			return { success: true, mode: 'wechat', response: res && (res.data || res) };
		} catch (err) {
			console.error('[Refund] Failed to initiate WeChat refund:', err);
			return { success: false, error: err };
		}
	}

	/**
	 * 退还余额
	 * @param {string} userId 用户ID
	 * @param {number} amount 退还金额
	 */
	async refundToBalance(userId, amount) {
		// 兜底：确保用户存在，缺失则自动建档再退款入账
		const user = await this.ensureUserExists(userId);
		await UserModel.edit({ _id: userId }, {
			balance: (user?.balance || 0) + amount,
			updateTime: timeUtil.time()
		});
	}

	/**
	 * 获取交易类型
	 * @param {number} status 预约状态
	 * @returns {string} 交易类型
	 */
	getTransactionType(status) {
		switch (status) {
			case AppointmentModel.STATUS.PAID:
			case AppointmentModel.STATUS.IN_SERVICE:
			case AppointmentModel.STATUS.COMPLETED:
				return 'payment';
			case AppointmentModel.STATUS.CANCELLED:
				return 'refund';
			default:
				return 'unknown';
		}
	}

	/**
	 * 获取交易状态
	 * @param {number} status 预约状态
	 * @returns {string} 交易状态
	 */
	getTransactionStatus(status) {
		switch (status) {
			case AppointmentModel.STATUS.PAID:
			case AppointmentModel.STATUS.IN_SERVICE:
			case AppointmentModel.STATUS.COMPLETED:
				return 'success';
			case AppointmentModel.STATUS.CANCELLED:
				return 'refunded';
			default:
				return 'pending';
		}
	}

	/**
	 * 获取交易描述
	 * @param {Object} appointment 预约信息
	 * @returns {string} 交易描述
	 */
	getTransactionDescription(appointment) {
		switch (appointment.status) {
			case AppointmentModel.STATUS.PAID:
			case AppointmentModel.STATUS.IN_SERVICE:
			case AppointmentModel.STATUS.COMPLETED:
				return `预约服务 - ${appointment.appointmentNumber}`;
			case AppointmentModel.STATUS.CANCELLED:
				return `退款 - ${appointment.appointmentNumber}`;
			default:
				return '未知交易';
		}
	}

	/**
	 * 生成随机字符串
	 * @returns {string} 随机字符串
	 */
	generateNonceStr() {
		return Math.random().toString(36).substr(2, 15);
	}

	/**
	 * 生成支付签名
	 * @param {Object} appointment 预约信息
	 * @returns {string} 支付签名
	 */
	generatePaySign(appointment) {
		// 这里应该使用微信支付签名算法
		// 暂时返回模拟签名
		return 'mock_pay_sign_' + appointment._id;
	}

	// ==================== 充值相关方法 ====================

	/**
	 * 创建充值订单
	 * @param {string} userId 用户ID
	 * @param {number} amount 充值金额（分）
	 * @param {number} bonus 赠送金额（分）
	 * @param {string} packageId 充值套餐ID
	 * @returns {Object} 充值订单信息
	 */
	async createRechargeOrder(userId, amount, bonus = 0, packageId = '') {
		// 验证用户是否存在（兜底自动建档）
		const user = await this.ensureUserExists(userId);
		if (!user) {
			throw new Error('用户不存在');
		}

		// 创建充值订单
		const rechargeModel = new RechargeModel();
		const orderData = {
			userId: userId,
			amount: amount,
			bonus: bonus,
			packageId: packageId
		};

		const orderId = await rechargeModel.createOrder(orderData);
		if (!orderId) {
			throw new Error('创建充值订单失败');
		}
		
		// 获取完整的订单信息
		const order = await RechargeModel.getOne({ _id: orderId });
		if (!order) {
			throw new Error('获取充值订单信息失败');
		}

		// 生成支付参数
		const paymentParams = await this.generateRechargePaymentParams(order);
		// 在调试模式且未启用真实微信支付时，标记前端模拟支付
		if (config && config.TEST_MODE && !config.TEST_CONFIG.ENABLE_REAL_WECHAT_PAY) {
			paymentParams._isTestMode = true;
		}

		return {
			rechargeOrderId: order._id,
			orderNumber: order.orderNumber,
			amount: order.amount,
			bonus: order.bonus,
			totalAmount: order.totalAmount,
			paymentParams: paymentParams
		};
	}

	/**
	 * 处理充值支付回调
	 * @param {string} rechargeOrderId 充值订单ID
	 * @param {Object} paymentResult 支付结果
	 * @returns {Object} 处理结果
	 */
	async handleRechargeCallback(rechargeOrderId, paymentResult) {
		console.log('[Recharge][Callback] 开始处理充值回调:', { rechargeOrderId, paymentResult });
		const { transactionId, payTime, status } = paymentResult;

		// 获取充值订单信息
		const rechargeModel = new RechargeModel();
		
		// 检查并取消过期订单（如果订单已过期，会自动取消）
		await rechargeModel.checkAndCancelExpiredOrder(rechargeOrderId, 30);
		
		const order = await rechargeModel.getOrderDetail(rechargeOrderId);
		console.log('[Recharge][Callback] 订单查询结果:', { orderId: rechargeOrderId, found: !!order });
		if (!order) {
			throw new Error('充值订单不存在');
		}

		// 检查订单状态
		console.log('[Recharge][Callback] 订单当前状态:', order.status);
		if (!RechargeModel.canPay(order)) {
			throw new Error('充值订单状态不允许支付');
		}

		if (status === 'success') {
			console.log('[Recharge][Callback] 支付成功，更新订单状态并增加余额');
			// 支付成功，更新订单状态
			await rechargeModel.updateStatus(rechargeOrderId, RechargeModel.STATUS.PAID, {
				payTime: payTime || timeUtil.time(),
				transactionId: transactionId || ''
			});

			// 更新用户余额
			console.log('[Recharge][Callback] 准备增加用户余额:', { userId: order.userId, amount: order.totalAmount });
			await this.addUserBalance(order.userId, order.totalAmount);
			console.log('[Recharge][Callback] 用户余额已增加');

			return {
				success: true,
				message: '充值成功',
				rechargeOrderId: rechargeOrderId,
				amount: order.totalAmount
			};
		} else {
			console.log('[Recharge][Callback] 支付失败');
			// 支付失败，更新订单状态
			await rechargeModel.updateStatus(rechargeOrderId, RechargeModel.STATUS.FAILED);

			return {
				success: false,
				message: '充值失败',
				rechargeOrderId: rechargeOrderId
			};
		}
	}

	/**
	 * 增加用户余额
	 * @param {string} userId 用户ID
	 * @param {number} amount 增加金额（分）
	 * @returns {Object} 更新结果
	 */
	async addUserBalance(userId, amount) {
		console.log('[addUserBalance] 开始增加用户余额:', { userId, amount });
		const user = await this.ensureUserExists(userId);
		if (!user) {
			throw new Error('用户不存在');
		}

		const oldBalance = user.balance || 0;
		const newBalance = oldBalance + amount;
		console.log('[addUserBalance] 余额计算:', { 
			userId, 
			oldBalance, 
			amount, 
			newBalance 
		});
		
		const result = await UserModel.edit({ _id: userId }, {
			balance: newBalance,
			updateTime: timeUtil.time()
		});
		
		console.log('[addUserBalance] ✅ 余额更新完成:', { 
			userId, 
			oldBalance, 
			newBalance, 
			result 
		});
		
		return result;
	}

	/**
	 * 余额支付充值订单
	 * @param {string} rechargeOrderId 充值订单ID
	 * @param {string} userId 用户ID
	 * @returns {Object} 支付结果
	 */


	/**
	 * 获取用户充值记录
	 * @param {string} userId 用户ID
	 * @param {number} page 页码
	 * @param {number} size 每页数量
	 * @returns {Object} 充值记录列表
	 */
	async getUserRechargeRecords(userId, page = 1, size = 20) {
		const rechargeModel = new RechargeModel();
		
		// 在查询前取消用户所有待支付的充值订单
		await rechargeModel.cancelUserPendingOrders(userId);
		
		// 在查询前检查并取消过期订单
		await rechargeModel.cancelExpiredOrders(30); // 30分钟过期
		
		const result = await rechargeModel.getUserOrders(userId, page, size);

		if (result && result.list) {
			// 格式化充值记录
			result.list = result.list.map(order => ({
				id: order._id,
				orderNumber: order.orderNumber,
				type: 'recharge',
				amount: order.totalAmount,
				status: this.getRechargeStatus(order.status),
				time: order.payTime || order.createTime,
				description: `账户充值 - ${order.orderNumber}`,
				originalAmount: order.amount,
				bonusAmount: order.bonus
			}));
		}


		return result;
	}

	/**
	 * 获取充值订单状态的描述文本
	 * @param {number} status 充值订单状态码
	 * @returns {string} 状态描述文本 (e.g., 'success', 'pending', 'failed', 'cancelled')
	 */
	getRechargeStatus(status) {
		const RechargeModel = require('../model/recharge_model.js');
		switch (status) {
			case RechargeModel.STATUS.PAID:
				return 'success';
			case RechargeModel.STATUS.PENDING:
				return 'pending';
			case RechargeModel.STATUS.FAILED:
				return 'failed';
			case RechargeModel.STATUS.CANCELLED:
				return 'cancelled';
			default:
				return 'unknown';
		}
	}

	/**
	 * 生成充值支付参数
	 * @param {Object} order 充值订单信息
	 * @returns {Object} 支付参数
	 */
	async generateRechargePaymentParams(order) {
		// 获取用户 openid（系统中 userId 等同于 openid）
		const user = await this.ensureUserExists(order.userId);
		if (!user) throw new Error('用户不存在');

		// 修正并清洗通知地址，去除反引号与空格
		let notifyBase = (config.WXPAY.NOTIFY_BASE_URL || '').toString().trim().replace(/^`|`$/g, '');
		const notifyPath = (config.WXPAY.NOTIFY_RECHARGE_PATH || '').toString().trim().replace(/^`|`$/g, '');
		// 确保 notifyBase 包含 https:// 协议
		if (notifyBase && !notifyBase.startsWith('http://') && !notifyBase.startsWith('https://')) {
			notifyBase = 'https://' + notifyBase;
		}
		const notifyUrl = `${notifyBase}${notifyPath}`;
		console.log('[Recharge] 最终 notify_url:', notifyUrl);
		console.log('[Recharge] JSAPI notify_url:', notifyUrl, 'FORCE_ONE_CENT=', !!config.WXPAY.FORCE_ONE_CENT);
		const amountTotal = config.WXPAY.FORCE_ONE_CENT ? 1 : order.totalAmount;
		if (config.WXPAY.FORCE_ONE_CENT) console.warn('[ForceOneCent] Recharge JSAPI amount forced to 1 cent');

		// 若未启用真实微信支付，返回测试模式支付参数
		console.log('[Recharge] TEST_CONFIG.ENABLE_REAL_WECHAT_PAY =', config.TEST_CONFIG.ENABLE_REAL_WECHAT_PAY);
		if (!config.TEST_CONFIG.ENABLE_REAL_WECHAT_PAY) {
			console.log('[Recharge] 测试模式：返回模拟支付参数');
			return { _isTestMode: true };
		}

		// 启用真实微信支付：直接使用 wechatpay-node-v3
		try {
			const wxPay = this._getWxPayClient();
			const params = {
				appid: config.WXPAY.APPID,
				mchid: config.WXPAY.MCHID,
				description: `账户充值-${order.orderNumber}`,
				out_trade_no: order.orderNumber,
				notify_url: notifyUrl,
				amount: { total: amountTotal },
				payer: { openid: user._id },
			};
		console.log('[Recharge] 发起微信支付请求，openid:', user._id, 'amount:', amountTotal, '分');
		const result = await wxPay.transactions_jsapi(params);
		console.log('[Recharge] 微信支付响应状态:', result?.status);
		const resData = result && (result.data || result);
		console.log('[Recharge] 响应数据key:', Object.keys(resData || {}));
			let payParams;
			if (resData && resData.package && (resData.paySign || resData.sign)) {
				payParams = {
					timeStamp: String(resData.timeStamp || resData.timestamp || Math.floor(Date.now() / 1000)),
					nonceStr: resData.nonceStr || resData.noncestr || (this.generateNonceStr ? this.generateNonceStr() : Math.random().toString(36).slice(2, 18)),
					package: resData.package,
					signType: resData.signType || 'RSA',
					paySign: resData.paySign || resData.sign,
				};
			} else {
				let prepayId = resData && resData.prepay_id;
				if (!prepayId && resData && typeof resData.package === 'string' && resData.package.startsWith('prepay_id=')) {
					prepayId = resData.package.replace('prepay_id=', '').trim();
				}
				console.log('[Recharge] 提取到的 prepay_id:', prepayId);
				if (!prepayId) throw new Error('微信下单失败：未返回 prepay_id');
			const appId = config.WXPAY.APPID;
			const timeStamp = String(Math.floor(Date.now() / 1000));
			const nonceStr = this.generateNonceStr ? this.generateNonceStr() : Math.random().toString(36).slice(2, 18);
			const payPackage = `prepay_id=${prepayId}`;
			const message = `${appId}\n${timeStamp}\n${nonceStr}\n${payPackage}\n`;
			const privateKeyPem = fs.readFileSync(config.WXPAY.MCH_PRIVKEY_PATH, 'utf8');
			const signer = crypto.createSign('RSA-SHA256');
			signer.update(message, 'utf8');
			signer.end();
				const paySign = signer.sign(privateKeyPem, 'base64');
				payParams = { timeStamp, nonceStr, package: payPackage, signType: 'RSA', paySign };
			}
			console.log('[Recharge] 返回支付参数:', payParams);
			return payParams;
		} catch (error) {
		console.error('[Recharge] 微信支付调用失败:', error.message);
		if (error.response) {
			console.error('[Recharge] 响应状态码:', error.response.status);
			console.error('[Recharge] 响应内容:', error.response.body);
		}
			throw new Error(`微信支付调用失败: ${error.message}`);
		}
	}

	/**
	 * 生成设备订单支付参数
	 * @param {Object} order 设备订单信息
	 * @returns {Object} 支付参数
	 */
	async generateDeviceOrderPaymentParams(order) {
		// 获取用户 openid（系统中 userId 等同于 openid）
		const user = await this.ensureUserExists(order.userId);
		if (!user) throw new Error('用户不存在');

		// 修正并清洗通知地址，去除反引号与空格
		let notifyBase = (config.WXPAY.NOTIFY_BASE_URL || '').toString().trim().replace(/^`|`$/g, '');
		const notifyPath = (config.WXPAY.NOTIFY_DEVICE_PATH || '').toString().trim().replace(/^`|`$/g, '');
		// 确保 notifyBase 包含 https:// 协议
		if (notifyBase && !notifyBase.startsWith('http://') && !notifyBase.startsWith('https://')) {
			notifyBase = 'https://' + notifyBase;
		}
		const notifyUrl = `${notifyBase}${notifyPath}`;
		const amountTotal = config.WXPAY.FORCE_ONE_CENT ? 1 : order.totalAmount;
		if (config.WXPAY.FORCE_ONE_CENT) console.warn('[ForceOneCent] Device JSAPI amount forced to 1 cent');

		// 若未启用真实微信支付，返回测试模式参数
		if (!config.TEST_CONFIG.ENABLE_REAL_WECHAT_PAY) {
			console.log('[Device] 测试模式：返回模拟支付参数');
			return { _isTestMode: true };
		}

		// 启用真实微信支付：直接使用 wechatpay-node-v3
		const wxPay = this._getWxPayClient();
		const params = {
			appid: config.WXPAY.APPID,
			mchid: config.WXPAY.MCHID,
			description: `设备使用-${order.orderNumber}`,
			out_trade_no: order.orderNumber,
			notify_url: notifyUrl,
			amount: { total: amountTotal },
			payer: { openid: user._id },
		};
		const result = await wxPay.transactions_jsapi(params);
		const resData = result && (result.data || result);
		let payParams;
		if (resData && resData.package && (resData.paySign || resData.sign)) {
			payParams = {
				timeStamp: String(resData.timeStamp || resData.timestamp || Math.floor(Date.now() / 1000)),
				nonceStr: resData.nonceStr || resData.noncestr || (this.generateNonceStr ? this.generateNonceStr() : Math.random().toString(36).slice(2, 18)),
					package: resData.package,
					signType: resData.signType || 'RSA',
					paySign: resData.paySign || resData.sign,
				};
			} else {
				let prepayId = resData && resData.prepay_id;
				if (!prepayId && resData && typeof resData.package === 'string' && resData.package.startsWith('prepay_id=')) {
					prepayId = resData.package.replace('prepay_id=', '').trim();
				}
				console.log('[Device] 提取到的 prepay_id:', prepayId);
				if (!prepayId) throw new Error('微信下单失败：未返回 prepay_id');
				const appId = config.WXPAY.APPID;
				const timeStamp = String(Math.floor(Date.now() / 1000));
				const nonceStr = this.generateNonceStr ? this.generateNonceStr() : Math.random().toString(36).slice(2, 18);
				const payPackage = `prepay_id=${prepayId}`;
				const message = `${appId}\n${timeStamp}\n${nonceStr}\n${payPackage}\n`;
				const privateKeyPem = fs.readFileSync(config.WXPAY.MCH_PRIVKEY_PATH, 'utf8');
				const signer = crypto.createSign('RSA-SHA256');
				signer.update(message, 'utf8');
				signer.end();
				const paySign = signer.sign(privateKeyPem, 'base64');
				payParams = { timeStamp, nonceStr, package: payPackage, signType: 'RSA', paySign };
			}
		console.log('[Device] 返回支付参数:', payParams);
		return payParams;
	}

	/**
	 * 微信支付 v3 回调：设备订单
	 * @param {Object} headers 回调请求头
	 * @param {string} bodyRaw 原始请求体字符串
	 * @returns {Object} 微信要求的返回 JSON
	 */
	async v3HandleDeviceCallback(headers, bodyRaw) {
		try {
			console.log('[DeviceCallback] ===== 开始处理设备订单回调 =====');
			
			// 1) 验签
			this._assertWechatHeaders(headers);
			const verified = this._verifyWechatSignature(headers, bodyRaw);
			if (!verified) {
				console.error('[DeviceCallback] 验签失败');
				return { code: 'FAIL', message: '验签失败' };
			}
			console.log('[DeviceCallback] 验签通过');

			// 2) 解密
			const notify = this._decryptWechatResource(bodyRaw);
			const outTradeNo = notify.out_trade_no;
			const transactionId = notify.transaction_id || '';
			const successTime = notify.success_time || '';
			const payTime = successTime ? Math.floor(new Date(successTime).getTime() / 1000) : timeUtil.time();
			
			console.log('[DeviceCallback] 解密成功:', {
				outTradeNo,
				transactionId: transactionId ? transactionId.substring(0, 20) + '...' : '',
				successTime,
				payTime
			});

			// 3) 订单更新（通过设备订单号映射，绕过PID过滤）
			console.log('[DeviceCallback] 查询设备订单，订单号:', outTradeNo);
			const order = await DeviceOrderModel.getOne({ orderNumber: outTradeNo }, '*', {}, false);
			if (!order) {
				console.error('[DeviceCallback] ❌ 设备订单不存在，订单号:', outTradeNo);
				return { code: 'FAIL', message: '设备订单不存在' };
			}
			console.log('[DeviceCallback] 找到订单:', {
				orderId: order._id,
				orderNumber: order.orderNumber,
				status: order.status,
				userId: order.userId
			});
			
			// 已处理幂等
			if (!DeviceOrderModel.canPay(order)) {
				console.log('[DeviceCallback] 订单已处理，状态:', order.status);
				return { code: 'SUCCESS', message: '已处理' };
			}

			console.log('[DeviceCallback] 开始支付处理...');
			const DeviceOrderService = require('./device_order_service.js');
			const deviceOrderService = new DeviceOrderService();
			await deviceOrderService.payDeviceOrder(order._id, 'wechat_pay', {
				transactionId,
				payTime,
				status: 'success'
			});

			console.log('[DeviceCallback] ✅ 支付处理成功');
			return { code: 'SUCCESS', message: '成功' };
		} catch (err) {
			console.error('[DeviceCallback] ❌ 处理失败:', err);
			console.error('[DeviceCallback] 错误堆栈:', err.stack);
			return { code: 'FAIL', message: '系统错误: ' + (err.message || String(err)) };
		}
	}
	/**
	 * 微信支付 v3 回调：预约订单
	 * @param {Object} headers 回调请求头
	 * @param {string} bodyRaw 原始请求体字符串
	 * @returns {Object} 微信要求的返回 JSON
	 */
	async v3HandleAppointmentCallback(headers, bodyRaw) {
		try {
			// 1) 验签
			this._assertWechatHeaders(headers);
			const verified = this._verifyWechatSignature(headers, bodyRaw);
			if (!verified) {
				return { code: 'FAIL', message: '验签失败' };
			}

			// 2) 解密
			const notify = this._decryptWechatResource(bodyRaw);
			const outTradeNo = notify.out_trade_no;
			const transactionId = notify.transaction_id || '';
			const successTime = notify.success_time || '';
			const payTime = successTime ? Math.floor(new Date(successTime).getTime() / 1000) : timeUtil.time();

			// 3) 订单更新（通过预约单号映射）
			const appointment = await AppointmentModel.getOne({ appointmentNumber: outTradeNo });
			if (!appointment) {
				return { code: 'FAIL', message: '预约单不存在' };
			}
			// 幂等处理：若非待支付直接返回成功
			if (appointment.status !== AppointmentModel.STATUS.PENDING_PAY) {
				return { code: 'SUCCESS', message: '已处理' };
			}

			// 4) 容量二次校验（排除当前预约自身）
			try {
				const AppointmentService = require('./appointment_service.js');
				const apptSvc = new AppointmentService();
				await apptSvc.checkTimeConflict(
					appointment.storeId,
					appointment.serviceId,
					appointment.appointmentTime,
					appointment.appointmentEndTime,
					appointment.employeeId || '',
					appointment.deviceId || '',
					appointment._id
				);
			} catch (e) {
				console.warn('[CapacityCheck] v3 回调容量校验失败:', e && e.message ? e.message : e);
				// 容量不足：将订单置为已取消，避免超售，同时触发自动退款
				await this.initiateWechatRefundForAppointment(appointment, '容量不足自动退款');
				await AppointmentModel.edit({ _id: appointment._id }, {
					status: AppointmentModel.STATUS.CANCELLED,
					updateTime: timeUtil.time()
				});
				return { code: 'FAIL', message: '容量不足，订单已取消' };
			}

			// 5) 正常置为已支付
			await AppointmentModel.edit({ _id: appointment._id }, {
				status: AppointmentModel.STATUS.PAID,
				payTime,
				updateTime: timeUtil.time()
			});

			return { code: 'SUCCESS', message: '成功' };
		} catch (err) {
			console.error('v3HandleAppointmentCallback error:', err);
			return { code: 'FAIL', message: '系统错误' };
		}
	}

	/**
	 * 微信支付 v3 回调：充值订单
	 * @param {Object} headers 回调请求头
	 * @param {string} bodyRaw 原始请求体字符串
	 * @returns {Object} 微信要求的返回 JSON
	 */
	async v3HandleRechargeCallback(headers, bodyRaw) {
		try {
			// 详细的入口日志：完整请求信息
			console.log('[Recharge] ===== 微信支付充值回调开始 =====');
			// console.log('[Recharge] 回调时间:', new Date().toISOString());
			// console.log('[Recharge] 完整请求头:', headers);
			// console.log('[Recharge] 请求体信息:', {
			// 	bodyRawType: typeof bodyRaw,
			// 	bodyRawLength: bodyRaw ? bodyRaw.length : 0,
			// 	bodyRawExists: !!bodyRaw,
			// 	bodyRawSample: bodyRaw ? bodyRaw.substring(0, 300) + (bodyRaw.length > 300 ? '...' : '') : null
			// });
			
			// 微信支付特定头信息提取
			const wxHeaders = {
				wxTimestamp: headers['Wechatpay-Timestamp'] || headers['wechatpay-timestamp'],
				wxNonce: headers['Wechatpay-Nonce'] || headers['wechatpay-nonce'],
				wxSignature: headers['Wechatpay-Signature'] || headers['wechatpay-signature'],
				wxSerial: headers['Wechatpay-Serial'] || headers['wechatpay-serial']
			};
			// console.log('[Recharge] 微信支付头信息提取:', wxHeaders);
			
			// 检查必要头信息是否存在
			const missingHeaders = [];
			if (!wxHeaders.wxTimestamp) missingHeaders.push('Wechatpay-Timestamp');
			if (!wxHeaders.wxNonce) missingHeaders.push('Wechatpay-Nonce');
			if (!wxHeaders.wxSignature) missingHeaders.push('Wechatpay-Signature');
			if (!wxHeaders.wxSerial) missingHeaders.push('Wechatpay-Serial');
			
			if (missingHeaders.length > 0) {
				console.error('[Recharge] 缺少必要的微信支付头信息:', missingHeaders);
				console.error('[Recharge] 所有可用头信息键:', Object.keys(headers));
			}

			// 1) 验签
			this._assertWechatHeaders(headers);
			const verified = this._verifyWechatSignature(headers, bodyRaw);
			console.log('[Recharge] v3 verify result=', verified);
			if (!verified) {
				return { code: 'FAIL', message: '验签失败' };
			}

			// 2) 解密
			const notify = this._decryptWechatResource(bodyRaw);
			console.log('[Recharge] v3 notify decrypted:', {
				out_trade_no: notify.out_trade_no,
				transaction_id: notify.transaction_id,
				success_time: notify.success_time,
				amount_total: notify.amount && notify.amount.total
			});
			const outTradeNo = notify.out_trade_no;
			const transactionId = notify.transaction_id || '';
			const successTime = notify.success_time || '';
			const payTime = successTime ? Math.floor(new Date(successTime).getTime() / 1000) : timeUtil.time();

		// 3) 订单更新（通过充值订单号映射）
		const order = await RechargeModel.getOne({ orderNumber: outTradeNo });
		console.log('[Recharge] find order by outTradeNo=', outTradeNo, 'found=', !!order);
		if (!order) {
			console.error('[Recharge] ❌ 充值订单不存在，订单号:', outTradeNo);
			return { code: 'FAIL', message: '充值订单不存在' };
		}
		
		console.log('[Recharge] 📋 订单详情:', {
			orderId: order._id,
			orderNumber: order.orderNumber,
			userId: order.userId,
			amount: order.amount,
			bonus: order.bonus,
			totalAmount: order.totalAmount,
			currentStatus: order.status
		});
		
		// 已处理幂等
		if (!RechargeModel.canPay(order)) {
			console.log('[Recharge] ⚠️ 订单已处理，跳过. status=', order.status);
			return { code: 'SUCCESS', message: '已处理' };
		}

		const rechargeModel = new RechargeModel();
		console.log('[Recharge] 🔄 准备更新订单状态为已支付...');
		await rechargeModel.updateStatus(order._id, RechargeModel.STATUS.PAID, {
			payTime,
			transactionId
		});
		console.log('[Recharge] ✅ 订单状态已更新为已支付.', { 
			rechargeOrderId: order._id, 
			userId: order.userId, 
			payTime, 
			transactionId 
		});
		
		// 获取更新前用户余额
		const userBefore = await UserModel.getOne({ _id: order.userId });
		const balanceBefore = userBefore ? (userBefore.balance || 0) : 0;
		console.log('[Recharge] 💰 更新前用户余额:', { userId: order.userId, balanceBefore });
		
		await this.addUserBalance(order.userId, order.totalAmount);
		
		// 验证余额更新结果
		const userAfter = await UserModel.getOne({ _id: order.userId });
		const balanceAfter = userAfter ? (userAfter.balance || 0) : 0;
		console.log('[Recharge] ✅ 用户余额已增加.', { 
			userId: order.userId, 
			amount: order.totalAmount,
			balanceBefore,
			balanceAfter,
			expectedBalance: balanceBefore + order.totalAmount,
			balanceUpdated: balanceAfter === (balanceBefore + order.totalAmount)
		});

			return { code: 'SUCCESS', message: '成功' };
		} catch (err) {
			console.error('v3HandleRechargeCallback error:', err && err.stack ? err.stack : err);
			return { code: 'FAIL', message: '系统错误' };
		}
	}

	/**
	 * 微信支付 v3 回调：退款通知（预约订单）
	 * @param {Object} headers 回调请求头
	 * @param {string} bodyRaw 原始请求体字符串
	 * @returns {Object} 微信要求的返回 JSON
	 */
	async v3HandleRefundCallback(headers, bodyRaw) {
		try {
			// 1) 验签
			this._assertWechatHeaders(headers);
			const verified = this._verifyWechatSignature(headers, bodyRaw);
			if (!verified) {
				return { code: 'FAIL', message: '验签失败' };
			}

			// 2) 解密
			const notify = this._decryptWechatResource(bodyRaw);
			const outTradeNo = notify.out_trade_no || '';
			const refundStatus = String(notify.refund_status || '').toUpperCase();

			// 3) 仅处理成功退款
			if (refundStatus !== 'SUCCESS') {
				return { code: 'SUCCESS', message: '忽略非成功退款状态' };
			}

			// 4) 订单更新（通过预约单号映射）
			if (!outTradeNo) {
				return { code: 'FAIL', message: '缺少订单号' };
			}
			const upper = outTradeNo.toUpperCase();
			// 仅处理预约订单退款
			if (upper.startsWith('APT')) {
				const appointment = await AppointmentModel.getOne({ appointmentNumber: outTradeNo });
				if (!appointment) {
					return { code: 'FAIL', message: '预约单不存在' };
				}
				// 幂等：已取消(视为已退款)
				if (appointment.status === AppointmentModel.STATUS.CANCELLED) {
					return { code: 'SUCCESS', message: '已处理' };
				}
				// 仅对已支付订单做退款入账与状态更新
				if (appointment.status === AppointmentModel.STATUS.PAID) {
					await AppointmentModel.edit({ _id: appointment._id }, {
						status: AppointmentModel.STATUS.CANCELLED,
						updateTime: timeUtil.time()
					});
					return { code: 'SUCCESS', message: '成功' };
				}
			}
			// 其他类型暂不处理，直接成功避免反复推送
			return { code: 'SUCCESS', message: '忽略非预约订单退款' };
		} catch (err) {
			console.error('v3HandleRefundCallback error:', err);
			return { code: 'FAIL', message: '系统错误' };
		}
	}

	// ==================== CloudPay 直调回调处理 ====================

	/**
	 * CloudPay 回调：退款通知（返回纯文本，仅处理预约订单）
	 * @param {Object} event CloudPay 事件对象
	 * @returns {string} 'SUCCESS' | 'FAIL'
	 */
	async cloudHandleRefundCallback(event) {
		try {
			const outTradeNo = event.outTradeNo || event.out_trade_no || '';
			const outRefundNo = event.outRefundNo || event.out_refund_no || '';
			if (!outTradeNo && !outRefundNo) return 'FAIL';
			const upper = String(outTradeNo || '').toUpperCase();

			// 仅在本地开发（LOCAL_DEV=1）且缺少腾讯云凭证时，跳过数据库操作
			if (process.env.LOCAL_DEV === '1' && (!process.env.TENCENTCLOUD_SECRETID || !process.env.TENCENTCLOUD_SECRETKEY)) {
				console.warn('Local dev: missing Tencent Cloud credentials, skip DB ops for cloudHandleRefundCallback');
				return 'SUCCESS';
			}

			// 仅处理预约订单退款
			if (upper.startsWith('APT')) {
				const appointment = await AppointmentModel.getOne({ appointmentNumber: outTradeNo });
				if (!appointment) return 'FAIL';
				// 幂等：已取消视为已退款
				if (appointment.status === AppointmentModel.STATUS.CANCELLED) return 'SUCCESS';
				// 仅对已支付订单做状态更新
				if (appointment.status === AppointmentModel.STATUS.PAID) {
					await AppointmentModel.edit({ _id: appointment._id }, {
						status: AppointmentModel.STATUS.CANCELLED,
						updateTime: timeUtil.time()
					});
					return 'SUCCESS';
				}
			}
			// 未识别类型，直接返回成功避免重复推送
			return 'SUCCESS';
		} catch (err) {
			console.error('cloudHandleRefundCallback error:', err);
			if (err && err.errMsg && err.errMsg.includes('missing secretId or secretKey')) return 'SUCCESS';
			return 'FAIL';
		}
	}

	/**
	 * CloudPay 回调：预约订单（返回纯文本）
	 * @param {Object} event CloudPay 事件对象
	 * @returns {string} 'SUCCESS' | 'FAIL'
	 */
	async cloudHandleAppointmentCallback(event) {
		try {
			const outTradeNo = event.outTradeNo || event.out_trade_no;
			if (!outTradeNo) return 'FAIL';
			// 仅在本地开发（LOCAL_DEV=1）且缺少腾讯云凭证时，跳过数据库操作
			if (process.env.LOCAL_DEV === '1' && (!process.env.TENCENTCLOUD_SECRETID || !process.env.TENCENTCLOUD_SECRETKEY)) {
				console.warn('Local dev: missing Tencent Cloud credentials, skip DB ops for cloudHandleAppointmentCallback');
				return 'SUCCESS';
			}
			const appointment = await AppointmentModel.getOne({ appointmentNumber: outTradeNo });
			if (!appointment) return 'FAIL';
			// 幂等处理：若非待支付直接返回成功
			if (appointment.status !== AppointmentModel.STATUS.PENDING_PAY) return 'SUCCESS';

			// 容量二次校验（排除当前预约自身）
			try {
				const AppointmentService = require('./appointment_service.js');
				const apptSvc = new AppointmentService();
				await apptSvc.checkTimeConflict(
					appointment.storeId,
					appointment.serviceId,
					appointment.appointmentTime,
					appointment.appointmentEndTime,
					appointment.employeeId || '',
					appointment.deviceId || '',
					appointment._id
				);
			} catch (e) {
				console.warn('[CapacityCheck] CloudPay 回调容量校验失败:', e && e.message ? e.message : e);
				// 触发自动退款并取消预约
				await this.initiateWechatRefundForAppointment(appointment, '容量不足自动退款');
				await AppointmentModel.edit({ _id: appointment._id }, {
					status: AppointmentModel.STATUS.CANCELLED,
					updateTime: timeUtil.time()
				});
				return 'FAIL';
			}

			await AppointmentModel.edit({ _id: appointment._id }, {
				status: AppointmentModel.STATUS.PAID,
				payTime: timeUtil.time(),
				updateTime: timeUtil.time()
			});
			return 'SUCCESS';
		} catch (err) {
			console.error('cloudHandleAppointmentCallback error:', err);
			if (err && err.errMsg && err.errMsg.includes('missing secretId or secretKey')) return 'SUCCESS';
			return 'FAIL';
		}
	}

	/**
	 * CloudPay 回调：预约订单（返回纯文本）
	 * @param {Object} event CloudPay 事件对象
	 * @returns {string} 'SUCCESS' | 'FAIL'
	 */
	async cloudHandleRechargeCallback(event) {
		try {
			console.log('[CloudPay] recharge callback event:', {
				outTradeNo: event.outTradeNo || event.out_trade_no,
				transactionId: event.transactionId || event.transaction_id,
				resultCode: event.resultCode || event.returnCode
			});
			const outTradeNo = event.outTradeNo || event.out_trade_no;
			if (!outTradeNo) return 'FAIL';
			// 仅在本地开发（LOCAL_DEV=1）且缺少腾讯云凭证时，跳过数据库操作
			if (process.env.LOCAL_DEV === '1' && (!process.env.TENCENTCLOUD_SECRETID || !process.env.TENCENTCLOUD_SECRETKEY)) {
				console.warn('Local dev: missing Tencent Cloud credentials, skip DB ops for cloudHandleRechargeCallback');
				return 'SUCCESS';
			}
			const rechargeModel = new RechargeModel();
			const order = await RechargeModel.getOne({ orderNumber: outTradeNo });
			console.log('[CloudPay] order lookup:', { outTradeNo, found: !!order });
			if (!order) return 'FAIL';
			// 幂等处理
			if (!RechargeModel.canPay(order)) {
				console.log('[CloudPay] order already processed. status=', order.status);
				return 'SUCCESS';
			}
			await rechargeModel.updateStatus(order._id, RechargeModel.STATUS.PAID, {
				payTime: timeUtil.time(),
				transactionId: event.transactionId || event.transaction_id || ''
			});
			console.log('[CloudPay] order status updated to PAID.', { rechargeOrderId: order._id });
			await this.addUserBalance(order.userId, order.totalAmount);
			console.log('[CloudPay] user balance credited.', { userId: order.userId, amount: order.totalAmount });
			return 'SUCCESS';
		} catch (err) {
			console.error('cloudHandleRechargeCallback error:', err && err.stack ? err.stack : err);
			if (err && err.errMsg && err.errMsg.includes('missing secretId or secretKey')) return 'SUCCESS';
			return 'FAIL';
		}
	}

	/**
	 * CloudPay 回调：设备订单（返回纯文本）
	 * @param {Object} event CloudPay 事件对象
	 * @returns {string} 'SUCCESS' | 'FAIL'
	 */
	async cloudHandleDeviceCallback(event) {
		try {
			const outTradeNo = event.outTradeNo || event.out_trade_no;
			if (!outTradeNo) return 'FAIL';
			// 仅在本地开发（LOCAL_DEV=1）且缺少腾讯云凭证时，跳过数据库操作
			if (process.env.LOCAL_DEV === '1' && (!process.env.TENCENTCLOUD_SECRETID || !process.env.TENCENTCLOUD_SECRETKEY)) {
				console.warn('Local dev: missing Tencent Cloud credentials, skip DB ops for cloudHandleDeviceCallback');
				return 'SUCCESS';
			}
			const order = await DeviceOrderModel.getOne({ orderNumber: outTradeNo });
			if (!order) return 'FAIL';
			// 幂等处理
			if (!DeviceOrderModel.canPay(order)) return 'SUCCESS';
			const DeviceOrderService = require('./device_order_service.js');
			const deviceOrderService = new DeviceOrderService();
			await deviceOrderService.payDeviceOrder(order._id, 'wechat_pay', {
				transactionId: event.transactionId || event.transaction_id || '',
				payTime: timeUtil.time(),
				status: 'success'
			});
			return 'SUCCESS';
		} catch (err) {
			console.error('cloudHandleDeviceCallback error:', err);
			if (err && err.errMsg && err.errMsg.includes('missing secretId or secretKey')) return 'SUCCESS';
			return 'FAIL';
		}
	}

	/**
	 * 内部：验证微信支付回调请求头
	 * @param {Object} headers 请求头对象
	 */
	_assertWechatHeaders(headers) {
		const timestamp = headers['Wechatpay-Timestamp'] || headers['wechatpay-timestamp'];
		const nonce = headers['Wechatpay-Nonce'] || headers['wechatpay-nonce'];
		const signature = headers['Wechatpay-Signature'] || headers['wechatpay-signature'];
		const serial = headers['Wechatpay-Serial'] || headers['wechatpay-serial'];

		if (!timestamp || !nonce || !signature || !serial) {
			console.error('[WxPay] Missing headers:', { timestamp, nonce, signature, serial });
			throw new Error('缺少必要的微信支付回调头信息');
		}
	}

	/**
	 * 内部：验证微信支付回调签名
	 * @param {Object} headers 请求头对象
	 * @param {string} bodyRaw 原始请求体
	 * @returns {boolean} 验签结果
	 */
	_verifyWechatSignature(headers, bodyRaw) {
		try {
			const timestamp = headers['Wechatpay-Timestamp'] || headers['wechatpay-timestamp'];
			const nonce = headers['Wechatpay-Nonce'] || headers['wechatpay-nonce'];
			const signature = headers['Wechatpay-Signature'] || headers['wechatpay-signature'];

			// 校验回包标识（平台证书序列号或平台公钥ID）
			const serialHeader = headers['Wechatpay-Serial'] || headers['wechatpay-serial'];
			if (config.WXPAY.PLATFORM_CERT_ID) {
				if (!serialHeader || serialHeader !== config.WXPAY.PLATFORM_CERT_ID) {
					console.error('[WxPay] Serial mismatch:', { serialHeader, expected: config.WXPAY.PLATFORM_CERT_ID });
					throw new Error('Wechatpay-Serial 与配置的平台公钥ID不一致');
				}
			}

			// 构建验签字符串
			const message = `${timestamp}\n${nonce}\n${bodyRaw}\n`;

			// 读取微信支付平台公钥
			const certPath = config.WXPAY.PLATFORM_CERT_PATH;
			if (!fs.existsSync(certPath)) {
				console.error('[WxPay] Certificate file does not exist:', certPath);
				throw new Error(`证书文件不存在: ${certPath}`);
			}

			const wechatPublicKey = fs.readFileSync(certPath, 'utf8');
			const hasCertHeader = wechatPublicKey.includes('-----BEGIN CERTIFICATE-----');
			const hasCertFooter = wechatPublicKey.includes('-----END CERTIFICATE-----');
			const hasPubHeader = wechatPublicKey.includes('-----BEGIN PUBLIC KEY-----');
			const hasPubFooter = wechatPublicKey.includes('-----END PUBLIC KEY-----');
			
			if (!((hasCertHeader && hasCertFooter) || (hasPubHeader && hasPubFooter))) {
				console.error('[WxPay] Invalid platform key/cert PEM format');
				throw new Error('平台证书/公钥文件格式不正确');
			}

			// 验证签名
			const verifier = crypto.createVerify('RSA-SHA256');
			verifier.update(message, 'utf8');
			verifier.end();

			const result = verifier.verify(wechatPublicKey, signature, 'base64');
			
			if (!result) {
				console.error('[WxPay] ❌ 验签失败');
			}
			
			return result;
		} catch (err) {
			console.error('[WxPay] ❌ 验签异常:', err.message);
			return false;
		}
	}

	/**
	 * 内部：解密微信支付回调资源
	 * @param {string} bodyRaw 原始请求体
	 * @returns {Object} 解密后的通知数据
	 */
	_decryptWechatResource(bodyRaw) {
		try {
			// console.log('[WxPay] Decryption start:', {
			// 	bodyRawLength: bodyRaw ? bodyRaw.length : 0,
			// 	bodyRawType: typeof bodyRaw,
			// 	bodyRawSample: bodyRaw ? bodyRaw.substring(0, 200) + (bodyRaw.length > 200 ? '...' : '') : null
			// });

			let body;
			try {
				body = JSON.parse(bodyRaw);
				// console.log('[WxPay] Body parsed successfully:', {
				// 	bodyKeys: Object.keys(body),
				// 	hasResource: 'resource' in body,
				// 	eventType: body.event_type,
				// id: body.id
				// });
			} catch (parseErr) {
				console.error('[WxPay] Failed to parse bodyRaw as JSON:', parseErr.message);
				console.error('[WxPay] BodyRaw content:', bodyRaw);
				throw new Error('回调数据不是有效的JSON格式');
			}

			const resource = body.resource;
			// console.log('[WxPay] Resource structure analysis:', {
			// 	hasResource: !!resource,
			// 	resourceType: typeof resource,
			// 	resourceKeys: resource ? Object.keys(resource) : null,
			// 	hasCiphertext: !!(resource && resource.ciphertext),
			// 	hasNonce: !!(resource && resource.nonce),
			// 	hasAssociatedData: !!(resource && resource.associated_data),
			// 	algorithm: resource && resource.algorithm,
			// 	ciphertextLength: resource && resource.ciphertext ? resource.ciphertext.length : 0,
			// 	nonceLength: resource && resource.nonce ? resource.nonce.length : 0,
			// 	associatedDataLength: resource && resource.associated_data ? resource.associated_data.length : 0
			// });

			if (!resource || !resource.ciphertext || !resource.nonce || !resource.associated_data) {
				console.error('[WxPay] Invalid resource structure - missing required fields:', {
					resource,
					hasCiphertext: !!(resource && resource.ciphertext),
					hasNonce: !!(resource && resource.nonce),
					hasAssociatedData: !!(resource && resource.associated_data)
				});
				throw new Error('回调数据格式错误');
			}

			// 使用 API v3 密钥解密
			const apiV3Key = config.WXPAY.API_V3_KEY;
			// console.log('[WxPay] API v3 key check:', {
			// 	hasApiV3Key: !!apiV3Key,
			// 	apiV3KeyLength: apiV3Key ? apiV3Key.length : 0,
			// 	apiV3KeyType: typeof apiV3Key,
			// 	configPath: 'config.WXPAY.API_V3_KEY'
			// });

			if (!apiV3Key) {
				console.error('[WxPay] Missing API v3 key');
				throw new Error('缺少 API v3 密钥');
			}
			// console.log('[WxPay] API v3 key available, length:', apiV3Key.length);

			// // AES-256-GCM 解密
			// console.log('[WxPay] Starting AES-256-GCM decryption');
			
			try {
				// 使用crypto.createDecipheriv进行AES-256-GCM解密
				const nonceBuffer = Buffer.from(resource.nonce, 'utf8');
				const decipher = crypto.createDecipheriv('aes-256-gcm', apiV3Key, nonceBuffer);
				// console.log('[WxPay] Decipher created successfully');
				
				// 设置 AAD
				const aadBuffer = Buffer.from(resource.associated_data, 'utf8');
				decipher.setAAD(aadBuffer);
				// console.log('[WxPay] AAD set:', {
				// 	associatedData: resource.associated_data,
				// 	aadBufferLength: aadBuffer.length
				// });
				
				// 从密文中提取 AuthTag（最后16字节）
				const cipherBuffer = Buffer.from(resource.ciphertext, 'base64');
				const authTagLength = 16;
				const authTag = cipherBuffer.slice(-authTagLength);
				const actualCipher = cipherBuffer.slice(0, -authTagLength);
				
				// console.log('[WxPay] Cipher buffer analysis:', {
				// 	cipherBufferLength: cipherBuffer.length,
				// 	authTagLength: authTag.length,
				// 	actualCipherLength: actualCipher.length,
				// 	nonce: resource.nonce,
				// 	nonceLength: resource.nonce.length,
				// 	associatedData: resource.associated_data,
				// 	ciphertextBase64Length: resource.ciphertext.length
				// });
				
				// IV (nonce) 已在创建decipher时设置
				// 设置 AuthTag
				decipher.setAuthTag(authTag);

				// 执行解密
				const partial = decipher.update(actualCipher);
				const finalBuf = decipher.final();
				const decrypted = Buffer.concat([partial, finalBuf]).toString('utf8');

				// console.log('[WxPay] Decryption successful:', {
				// 	resultLength: decrypted.length,
				// 	resultPreview: decrypted.substring(0, 200) + (decrypted.length > 200 ? '...' : '')
				// });
				
				let result;
				try {
					result = JSON.parse(decrypted);
					// console.log('[WxPay] Decrypted data parsed successfully:', {
					// 	out_trade_no: result.out_trade_no,
					// 	transaction_id: result.transaction_id,
					// 	trade_state: result.trade_state,
					// 	success_time: result.success_time,
					// 	resultKeys: Object.keys(result)
					// });
				} catch (jsonErr) {
					console.error('[WxPay] Failed to parse decrypted data as JSON:', jsonErr.message);
					console.error('[WxPay] Decrypted content:', decrypted);
					throw new Error('解密后的数据不是有效的JSON格式');
				}
				
				return result;
			} catch (decryptErr) {
				console.error('[WxPay] AES-256-GCM decryption failed:', decryptErr.message);
				console.error('[WxPay] Decryption error details:', {
					errorName: decryptErr.name,
					errorCode: decryptErr.code,
					apiV3KeyLength: apiV3Key ? apiV3Key.length : 0,
					ciphertextLength: resource.ciphertext ? resource.ciphertext.length : 0,
					nonceLength: resource.nonce ? resource.nonce.length : 0,
					associatedDataLength: resource.associated_data ? resource.associated_data.length : 0
				});
				throw decryptErr;
			}
		} catch (err) {
			console.error('[WxPay] Decryption failed:', err.message);
			console.error('[WxPay] Error stack:', err.stack);
			throw new Error('解密回调数据失败: ' + err.message);
		}
	}

	/**
	 * 内部：获取微信支付 v3 客户端
	 * @returns {WxPay} wechatpay-node-v3 客户端实例
	 */
	_getWxPayClient() {
		// 按需加载 wechatpay-node-v3，避免 ESM 依赖冲突
		if (!WxPay) {
			WxPay = require('wechatpay-node-v3');
		}
		// wechatpay-node-v3 需要：publicKey（微信支付公钥）、privateKey（商户私钥）、serial_no（商户证书序列号）
		const merchantPrivateKey = fs.readFileSync(config.WXPAY.MCH_PRIVKEY_PATH, 'utf8');
		const merchantCertPem = fs.readFileSync(config.WXPAY.MCH_CERT_PATH, 'utf8');
		const wechatPublicKey = fs.readFileSync(config.WXPAY.PLATFORM_CERT_PATH, 'utf8');
		console.log('[WxPay] 加载证书成功');
		
		let serialNo = config.WXPAY.SERIAL_NO;
		if (!serialNo) {
			try {
				const { Certificate } = require('@fidm/x509');
				serialNo = Certificate.fromPEM(Buffer.from(merchantCertPem)).serialNumber;
			} catch (e) {
				console.error('Failed to parse merchant certificate serial number:', e);
			}
		}
		
		const wxPay = new WxPay({
			appid: config.WXPAY.APPID,
			mchid: config.WXPAY.MCHID,
			serial_no: serialNo,
			privateKey: merchantPrivateKey,
			publicKey: wechatPublicKey,
		});
		return wxPay;
	}

	/**
	 * 处理来自wxpayFunctions的预约订单回调
	 */
	async handleWxPayFunctionsAppointmentCallback(callbackData) {
		try {
			console.log('Processing wxpayFunctions appointment callback:', callbackData);
			
			// 从商户订单号中提取预约ID
			const appointmentId = this._extractOrderIdFromOutTradeNo(callbackData.out_trade_no, 'APPOINTMENT_');
			if (!appointmentId) {
				throw new Error('Invalid appointment order number format');
			}
			
			// 调用现有的预约回调处理逻辑
			return await this.handlePaymentCallback(appointmentId, {
				trade_state: callbackData.trade_state,
				transaction_id: callbackData.transaction_id,
				out_trade_no: callbackData.out_trade_no,
				total_fee: callbackData.amount ? callbackData.amount.total : 0,
				time_end: callbackData.success_time || new Date().toISOString()
			});
		} catch (error) {
			console.error('Error processing wxpayFunctions appointment callback:', error);
			throw error;
		}
	}

	/**
	 * 处理来自wxpayFunctions的设备订单回调
	 */
	async handleWxPayFunctionsDeviceCallback(callbackData) {
		try {
			console.log('Processing wxpayFunctions device callback:', callbackData);
			
			// 从商户订单号中提取设备订单ID
			const deviceOrderId = this._extractOrderIdFromOutTradeNo(callbackData.out_trade_no, 'DEVICE_ORDER_');
			if (!deviceOrderId) {
				throw new Error('Invalid device order number format');
			}
			
			// 调用内部设备订单回调处理方法
			return await this._handleDeviceOrderCallback(deviceOrderId, callbackData);
		} catch (error) {
			console.error('Error processing wxpayFunctions device callback:', error);
			throw error;
		}
	}

	/**
	 * 处理来自wxpayFunctions的充值订单回调
	 */
	async handleWxPayFunctionsRechargeCallback(callbackData) {
		try {
			console.log('Processing wxpayFunctions recharge callback:', callbackData);
			
			// 从商户订单号中提取充值订单ID
			const rechargeOrderId = this._extractOrderIdFromOutTradeNo(callbackData.out_trade_no, 'RECHARGE_');
			if (!rechargeOrderId) {
				throw new Error('Invalid recharge order number format');
			}
			
			// 调用现有的充值回调处理逻辑
			return await this.handleRechargeCallback(rechargeOrderId, {
				trade_state: callbackData.trade_state,
				transaction_id: callbackData.transaction_id,
				out_trade_no: callbackData.out_trade_no,
				total_fee: callbackData.amount ? callbackData.amount.total : 0,
				time_end: callbackData.success_time || new Date().toISOString()
			});
		} catch (error) {
			console.error('Error processing wxpayFunctions recharge callback:', error);
			throw error;
		}
	}

	/**
	 * 从商户订单号中提取订单ID
	 */
	_extractOrderIdFromOutTradeNo(outTradeNo, prefix) {
		if (!outTradeNo || !outTradeNo.startsWith(prefix)) {
			return null;
		}
		return outTradeNo.substring(prefix.length);
	}

	/**
	 * 内部处理设备订单回调
	 */
	async _handleDeviceOrderCallback(deviceOrderId, callbackData) {
		try {
			// 查找设备订单
			const deviceOrder = await DeviceOrderModel.getOne({ _id: deviceOrderId });
			if (!deviceOrder) {
				throw new Error(`Device order not found: ${deviceOrderId}`);
			}

			// 幂等处理：已支付则直接返回成功
			if (!DeviceOrderModel.canPay(deviceOrder)) {
				return { success: true, message: 'Order already processed' };
			}

			// 复用统一的设备订单微信支付逻辑（包含状态更新与设备启动/延时）
			const DeviceOrderService = require('./device_order_service.js');
			const deviceOrderService = new DeviceOrderService();
			const status = callbackData.trade_state === 'SUCCESS' ? 'success' : 'failed';
			const payTime = callbackData.success_time
				? Math.floor(new Date(callbackData.success_time).getTime() / 1000)
				: timeUtil.time();
			await deviceOrderService.payDeviceOrder(deviceOrder._id, 'wechat_pay', {
				transactionId: callbackData.transaction_id || callbackData.transactionId || '',
				payTime,
				status
			});

			if (status === 'success') {
				return { success: true, message: 'Payment processed successfully' };
			} else {
				return { success: false, message: `Payment ${callbackData.trade_state}` };
			}
		} catch (error) {
			console.error('Error handling device order callback:', error);
			throw error;
        }
    }

    /**
     * 查询微信支付订单（通过商户订单号）
     * 优先调用现有 wxpayFunctions 云函数以最小改动实现
     */
	async queryOrderByOutTradeNo(outTradeNo) {
		try {
			// TEST_MODE 下，本地没有腾讯云密钥时，直接模拟返回结构，避免 cloud.callFunction 报错
			if (config.TEST_MODE) {
				return {
					success: true,
					data: {
						trade_state: 'NOTPAY',
						out_trade_no: outTradeNo,
						transaction_id: 'TEST_MODE_TX_' + (outTradeNo || 'UNKNOWN'),
						amount: { total: 1, payer_total: 1, currency: 'CNY' },
						success_time: null
					}
				};
			}
			const cloud = cloudBase.getCloud();
			const result = await cloud.callFunction({
				name: 'wxpayFunctions',
				data: { type: 'wxpay_query_order_by_out_trade_no', out_trade_no: outTradeNo }
			});
			return result.result || result;
		} catch (err) {
			console.error('queryOrderByOutTradeNo failed:', err);
			return { success: false, message: 'query failed', error: err && (err.message || String(err)) };
		}
	}

	/**
	 * 查询微信支付订单（通过微信订单号）
	 * 优先调用现有 wxpayFunctions 云函数以最小改动实现
	 */
	async queryOrderByTransactionId(transactionId) {
		try {
			// TEST_MODE 下，本地没有腾讯云密钥时，直接模拟返回结构，避免 cloud.callFunction 报错
			if (config.TEST_MODE) {
				return {
					success: true,
					data: {
						trade_state: 'SUCCESS',
						transaction_id: transactionId,
						out_trade_no: 'TEST_MODE_OTN_' + (transactionId || 'UNKNOWN'),
						amount: { total: 1, payer_total: 1, currency: 'CNY' },
						success_time: new Date().toISOString()
					}
				};
			}
			const cloud = cloudBase.getCloud();
			const result = await cloud.callFunction({
				name: 'wxpayFunctions',
				data: { type: 'wxpay_query_order_by_transaction_id', transaction_id: transactionId }
			});
			return result.result || result;
		} catch (err) {
			console.error('queryOrderByTransactionId failed:', err);
			return { success: false, message: 'query failed', error: err && (err.message || String(err)) };
		}
	}

	/**
	 * 申请微信支付退款（直调 wxpayFunctions），兼容前端 /api/payment/refund
	 */
	async createWxPayRefund(refundData) {
		try {
			// TEST_MODE 下，本地没有腾讯云密钥时，直接模拟返回结构，避免 cloud.callFunction 报错
			if (config.TEST_MODE) {
				return {
					success: true,
					data: {
						status: 'SUCCESS',
						out_refund_no: refundData?.out_refund_no || 'TEST_MODE_RF_UNKNOWN',
						refund_id: 'TEST_MODE_RF_' + Math.random().toString(36).slice(2,10),
						out_trade_no: refundData?.out_trade_no || 'TEST_MODE_OTN_UNKNOWN',
						amount: { refund: refundData?.refund || 1, total: refundData?.total || 1, currency: 'CNY' },
						success_time: new Date().toISOString()
					}
				};
			}
			const cloud = cloudBase.getCloud();
			const result = await cloud.callFunction({
				name: 'wxpayFunctions',
				data: { type: 'wxpay_refund', ...refundData }
			});
			return result.result || result;
		} catch (err) {
			console.error('createWxPayRefund failed:', err);
			return { success: false, message: 'refund failed', error: err && (err.message || String(err)) };
		}
	}

}

module.exports = PaymentService;
